package tgeo;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.net.InetSocketAddress;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import org.apache.mina.common.ByteBuffer;
import org.apache.mina.common.IdleStatus;
import org.apache.mina.common.IoHandler;
import org.apache.mina.common.IoSession;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.part.ViewPart;

import tgeo.common.UDPClient;


public class UDPClientView extends ViewPart {
	public static final String ID = "tgeo.views.UDPClientView";

	
	Label lblHost = null;
	Text txtHost = null;
	Label lblPort = null;
	Text txtPort = null;
	Button btnConnection = null;
	Button btnDisconnection = null;

	Button btnSend = null;
	Text txtSend = null;
	Label lblSession = null;
	
	Text txtRecvDir = null;
	Button btnRecvDir = null;
	final int PAD = 10;
	String path = "";

	UDPClient client = null;
	IoHandler handler = null;
	@SuppressWarnings("unchecked")
	LinkedBlockingQueue queueRecv = null;
	Display display = null;
	byte[] oldBuf = null;

	Button radioHex = null;
	Button radioStr = null;
	Combo cboEncoding = null;

	Map<String, FileChannel> outFiles = null; // fileName, FileChannel
	Map<String, FileChannel> inFiles = null; // fileName, FileChannel

	public UDPClientView() {
		
	}

	@SuppressWarnings("unchecked")
	@Override
	public void createPartControl(final Composite parent) {
		display = parent.getDisplay();
		parent.setBackgroundMode(SWT.INHERIT_DEFAULT);
		FormData data = null;
		
		lblHost = new Label(parent, SWT.NONE);
		txtHost = new Text(parent, SWT.BORDER);
		lblPort = new Label(parent, SWT.NONE);
		txtPort = new Text(parent, SWT.BORDER);
		btnConnection = new Button(parent, SWT.PUSH);
		btnDisconnection = new Button(parent, SWT.PUSH);
		btnSend = new Button(parent, SWT.PUSH);
		txtSend = new Text(parent, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL
				| SWT.WRAP);
		lblSession = new Label(parent, SWT.NONE);
		txtRecvDir = new Text(parent, SWT.BORDER | SWT.READ_ONLY);
		btnRecvDir = new Button(parent, SWT.PUSH);

		Layout layout = new FormLayout();

		parent.setLayout(layout);

		Composite composite0 = new Composite(parent, SWT.NONE);
		composite0.setLayout(parent.getLayout());

		radioHex = new Button(composite0, SWT.RADIO);
		radioStr = new Button(composite0, SWT.RADIO);
		cboEncoding = new Combo(composite0, SWT.BORDER);

		radioHex.setText("Hex");
		radioStr.setText("Text");
		radioStr.setSelection(true);

		Map<String, Charset> mapCharset = Charset.availableCharsets();
		for (String k : mapCharset.keySet()) {
			Charset charset = mapCharset.get(k);
			cboEncoding.add(charset.toString());
		}
		cboEncoding.setText(Charset.defaultCharset().toString());

		lblHost.setText("Host");
		txtHost.setText("127.0.0.1");
		lblPort.setText("Port");
		btnConnection.setText("Connection");
		btnDisconnection.setText("DisConnection");
		btnSend.setText("Send");
		txtSend.setFont(new Font(null, "fixedsys", 10, SWT.NONE));
		btnRecvDir.setText("Receive Dir");
		txtRecvDir.setText((new File(".")).getAbsolutePath());

		data = new FormData();
		data.top = new FormAttachment(0, PAD);
		data.left = new FormAttachment(0, PAD);
		radioHex.setLayoutData(data);

		data = new FormData();
		data.top = new FormAttachment(radioHex, PAD);
		data.left = new FormAttachment(0, PAD);
		radioStr.setLayoutData(data);

		data = new FormData();
		data.top = new FormAttachment(radioHex, PAD);
		data.left = new FormAttachment(radioStr, PAD);
		cboEncoding.setLayoutData(data);

		data = new FormData();
		data.top = new FormAttachment(cboEncoding, PAD);
		data.left = new FormAttachment(0, PAD);
		lblHost.setLayoutData(data);

		data = new FormData();
		data.width = 150;
		data.top = new FormAttachment(cboEncoding, PAD);
		data.left = new FormAttachment(lblHost, PAD);
		txtHost.setLayoutData(data);
		
		data = new FormData();
		data.top = new FormAttachment(cboEncoding, PAD);
		data.left = new FormAttachment(txtHost, PAD);
		lblPort.setLayoutData(data);

		data = new FormData();
		data.top = new FormAttachment(cboEncoding, PAD);
		data.left = new FormAttachment(lblPort, PAD);
		txtPort.setLayoutData(data);

		data = new FormData();
		data.top = new FormAttachment(cboEncoding, PAD);
		data.left = new FormAttachment(txtPort, PAD);
		btnConnection.setLayoutData(data);

		data = new FormData();
		data.top = new FormAttachment(cboEncoding, PAD);
		data.left = new FormAttachment(btnConnection, PAD);
		btnDisconnection.setLayoutData(data);

		data = new FormData();
		data.top = new FormAttachment(btnDisconnection, PAD);
		data.right = new FormAttachment(100, -PAD);
		btnRecvDir.setLayoutData(data);

		data = new FormData();
		data.top = new FormAttachment(btnDisconnection, PAD);
		data.left = new FormAttachment(0, PAD);
		data.right = new FormAttachment(btnRecvDir, -PAD);
		txtRecvDir.setLayoutData(data);

		data = new FormData();
		data.top = new FormAttachment(txtRecvDir, PAD);
		data.left = new FormAttachment(0, PAD);
		btnSend.setLayoutData(data);

		data = new FormData();
		data.top = new FormAttachment(txtRecvDir, PAD);
		data.left = new FormAttachment(btnSend, PAD);
		data.right = new FormAttachment(100, -PAD);
		lblSession.setLayoutData(data);

		data = new FormData();
		data.top = new FormAttachment(btnSend, PAD);
		data.left = new FormAttachment(0, PAD);
		composite0.setLayoutData(data);

		data = new FormData();
		data.top = new FormAttachment(composite0, PAD);
		data.left = new FormAttachment(0, PAD);
		data.right = new FormAttachment(100, -PAD);
		data.bottom = new FormAttachment(100, -PAD);
		txtSend.setLayoutData(data);

//		sessions = new HashMap();
		queueRecv = new LinkedBlockingQueue();
		client = null;
		handler = new IoHandler() {
			@Override
			public void exceptionCaught(IoSession session, Throwable message)
					throws Exception {
				System.out.println(message.toString());
			}

			@Override
			public void messageReceived(IoSession session, Object message)
					throws Exception {
				try {
					ByteBuffer buf = (ByteBuffer) message;
					byte[] bytearr = new byte[buf.remaining()];
					System.out.println("received : " + buf.remaining());
					buf.get(bytearr);
					UDPJob job = new UDPJob(session, bytearr);
					queueRecv.add(job);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}

			@Override
			public void messageSent(IoSession arg0, Object arg1)
					throws Exception {
			}

			@Override
			public void sessionClosed(IoSession session) throws Exception {
				System.out.println("sessionClosed");
				closeSession(session);
			}

			@Override
			public void sessionCreated(IoSession arg0) throws Exception {
				System.out.println("sessionCreated");
			}

			@Override
			public void sessionIdle(IoSession arg0, IdleStatus arg1)
					throws Exception {
			}

			@Override
			public void sessionOpened(IoSession session) throws Exception {
				System.out.println("sessionOpened");
				openSession(session);
			}
		};

		btnConnection.addSelectionListener(new SelectionListener() {

			@Override
			public void widgetSelected(SelectionEvent e) {
				int port = Integer.parseInt(txtPort.getText(), 10);
				String host = txtHost.getText();
				if(client != null){
					client.close();
					client = null;
				}
				client = new UDPClient();
				try {
					client.connect(host, port, handler);
				} catch (Exception e1) {
					e1.printStackTrace();
				}

			}

			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
			}
		});
		btnDisconnection.addSelectionListener(new SelectionListener() {

			@Override
			public void widgetSelected(SelectionEvent e) {
				if (client == null)
					return;
				client.close();
			}

			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
			}
		});

		btnSend.addSelectionListener(new SelectionListener() {

			@Override
			public void widgetSelected(SelectionEvent e) {
				IoSession session = client.getConnectFuture().getSession();
				String msg = txtSend.getText();

				org.apache.mina.common.ByteBuffer buf = null;
				try {
					if (radioHex.getSelection()) {
						msg = msg.replaceAll("[^a-zA-Z0-9]", "");
						buf = org.apache.mina.common.ByteBuffer.allocate(msg
								.length() / 2);
						byte[] bytearr = new byte[msg.length() / 2];
						for (int i = 0; i < msg.length() / 2; i++) {
							bytearr[i] = (byte) (int) Integer.valueOf(msg
									.substring(i * 2, (i + 1) * 2), 16);
						}
						buf.put(bytearr);
					} else {
						buf = org.apache.mina.common.ByteBuffer.allocate(msg
								.getBytes().length);
						buf.put(msg.getBytes(cboEncoding.getText()));
					}

				} catch (/* UnsupportedEncoding */Exception e1) {
					e1.printStackTrace();
				}
				buf.flip();
				session.write(buf);
			}

			@Override
			public void widgetDefaultSelected(SelectionEvent e) {

			}
		});

		btnRecvDir.addSelectionListener(new SelectionListener() {

			@Override
			public void widgetSelected(SelectionEvent e) {

				DirectoryDialog dlg = new DirectoryDialog(parent.getShell());

				path = dlg.open();
				if (path == null)
					return;
				txtRecvDir.setText(path);
			}

			@Override
			public void widgetDefaultSelected(SelectionEvent e) {

			}
		});
		path = txtRecvDir.getText();

		(new Thread() {
			@Override
			public void run() {
				while (true) {
					try {
						UDPJob job = (UDPJob) queueRecv.take();
						if (job == null)
							continue;
						IoSession session = job.session;
						Object message = job.message;
						byte[] buf = (byte[]) message;
						FileOutputStream fos = null;
						InetSocketAddress addrLocal = (InetSocketAddress) session
								.getLocalAddress();
						InetSocketAddress addrRemote = (InetSocketAddress) session
								.getRemoteAddress();
						String dir = path + "/" + addrLocal.getPort();
						(new File(dir)).mkdirs();
						String saveFile = dir + "/" + addrRemote.getHostName()
								+ "_" + addrRemote.getPort();
						System.out.println(saveFile);
						try {
							fos = new FileOutputStream(saveFile, true);
							FileChannel fc = fos.getChannel();
							java.nio.ByteBuffer buff = java.nio.ByteBuffer
									.allocate(buf.length);
							buff.put(buf);
							buff.flip();
							fc.write(buff);
							fc.close();
						} catch (FileNotFoundException e1) {
							e1.printStackTrace();
						}
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		}).start();
	}

	@Override
	public void setFocus() {
	}

	void openSession(final IoSession session) {
//		String str = session.hashCode() + "" + session.getRemoteAddress();
		InetSocketAddress addrLocal = (InetSocketAddress) session
		.getLocalAddress();
		String str = addrLocal.getHostName() + "_" + addrLocal.getPort();
		System.out.println(str);
		display.syncExec(new Runnable() {
			@Override
			public void run() {
				String str = session.hashCode() + ""
						+ session.getLocalAddress();
				lblSession.setText(str);
			}
		});
	}

	void closeSession(final IoSession session) {
		client = null;
		InetSocketAddress addrLocal = (InetSocketAddress) session
		.getLocalAddress();
		String str = addrLocal.getHostName() + "_" + addrLocal.getPort();
//		String str = session.hashCode() + "" + session.getLocalAddress();
		System.out.println(str);
		display.syncExec(new Runnable() {
			@Override
			public void run() {
				lblSession.setText("");
			}
		});
	}
}
